<template>
  <view>
    <view class="content" @touchstart="hideDrawer">
      <scroll-view
        class="msg-list dialogue-box"
        scroll-y="true"
        :scroll-with-animation="scrollAnimation"
        :scroll-top="scrollTop"
        :scroll-into-view="scrollToView"
        @scrolltoupper="loadHistory"
        upper-threshold="50"
        bindscrolltolower="true"
      >
        <view class="dialogue-box-content">
          <view
            class="row"
            v-for="(row, index) in msgList"
            :key="index"
            :id="'msg' + row.msg.id"
          >
            <!-- 用户消息 -->
            <block v-if="row.type == 'user'">
              <!-- 自己发出的消息 -->
              <view class="my" v-if="row.msg.userinfo.uid == myuid">
                <!-- 左-消息 -->
                <view class="left">
                  <!-- 文字消息 -->
                  <view v-if="row.msg.type == 'text'" class="bubble">
                    <rich-text :nodes="row.msg.content.text"></rich-text>
                  </view>
                  <!-- 语言消息 -->
                  <view
                    v-if="row.msg.type == 'voice'"
                    class="bubble voice"
                    @tap="playVoice(row.msg)"
                    :class="playMsgid == row.msg.id ? 'play' : ''"
                  >
                    <view class="length">{{ row.msg.content.length }}</view>
                    <view class="icon my-voice"></view>
                  </view>
                  <!-- 图片消息 -->
                  <view
                    v-if="row.msg.type == 'img'"
                    class="bubble img"
                    @tap="showPic(row.msg)"
                  >
                    <image
                      :src="row.msg.content.url"
                      :style="{
                        width: row.msg.content.w + 'px',
                        height: row.msg.content.h + 'px',
                      }"
                    ></image>
                  </view>
                </view>
                <!-- 右-头像 -->
                <view class="right">
                  <image src="@/static/right-header.png"></image>
                </view>
              </view>

              <!-- 别人发出的消息 -->
              <view
                v-if="row.msg.userinfo.uid != myuid"
                style="
                  display: flex;
                  flex-direction: column;
                  /* align-items: flex-end; */
                "
              >
                <view class="other">
                  <!-- 左-头像 -->
                  <view class="left">
                    <image src="@/static/left-header.png"></image>
                  </view>
                  <!-- 右-用户名称-时间-消息 -->
                  <view class="right">
                    <!-- 文字消息 -->
                    <view v-if="row.msg.type == 'text'" class="bubble">
                      <rich-text :nodes="row.msg.content.text"></rich-text>
                    </view>
                    <!-- 语音消息 -->
                    <view
                      v-if="row.msg.type == 'voice'"
                      class="bubble voice"
                      @tap="playVoice(row.msg)"
                      :class="playMsgid == row.msg.id ? 'play' : ''"
                    >
                      <view class="icon other-voice"></view>
                      <view class="length">{{ row.msg.content.length }}</view>
                    </view>
                  </view>
                </view>
                <view
                  class="anawer-tips"
                  v-show="
                    index == msgList.length - 1 && appendContent && !ifStopSock
                  "
                  @click="stopSock"
                  >停止回答</view
                >
              </view>
            </block>
            <view v-if="index === 0" class="question-tips other">
              <view class="left">
                <image src="@/static/left-header.png"></image>
              </view>
              <view class="right">
                <view class="question-box">
                  <view class="title">常见</view>
                  <view class="red-img">
                    <image src="@/static/question-bg.png"></image>
                    <view class="title-1">问题</view>
                  </view>
                  <image src="@/static/question-icon.png" class="ques-icon"></image>
                </view>
                <view>
                  <view
                    v-for="(item, type) in questionList"
                    :key="type"
                    @click="questionBtn(item)"
                    class="question-item"
                    >{{ type + 1 }}、{{ item }}</view
                  >
                </view></view
              >
            </view>
          </view>
        </view>
      </scroll-view>
    </view>
    <!-- 抽屉栏 -->
    <!-- <view
      class="popup-layer"
      :class="popupLayerClass"
      @touchmove.stop.prevent="discard"
    >
    </view> -->
    <!-- 底部输入栏 -->
    <view
      class="input-box"
      :class="popupLayerClass"
      @touchmove.stop.prevent="discard"
    >
      <!-- H5下不能录音，输入栏布局改动一下 -->
      <!-- #ifndef H5 -->
      <view class="voice">
        <view
          class="icon"
          :class="isVoice ? 'jianpan' : 'yuyin'"
          @tap="switchVoice"
        ></view>
      </view>
      <!-- #endif -->
      <!-- #ifdef H5 -->
      <view class="more" @tap="showMore">
        <view class="icon add"></view>
      </view>
      <!-- #endif -->
      <view class="textbox">
        <view
          class="voice-mode"
          :class="[isVoice ? '' : 'hidden', recording ? 'recording' : '']"
          @touchstart="voiceBegin"
          @touchmove.stop.prevent="voiceIng"
          @touchend="voiceEnd"
          @touchcancel="voiceCancel"
          >{{ voiceTis }}</view
        >
        <view class="text-mode" :class="isVoice ? 'hidden' : ''">
          <view class="box">
            <textarea
              auto-height="true"
              v-model="textMsg"
              @focus="textareaFocus"
              :show-confirm-bar="false"
              :cursorSpacing="20"
            />
          </view>
        </view>
      </view>
      <view
        :class="isVoice ? 'hidden' : ''"
        @tap="sendText"
        style="width: 80rpx,height:100%;"
      >
        <image
          src="@/static/send-btn.png"
          style="
            width: 50rpx;
            height: 50rpx;
            margin-top: 25rpx;
            margin-left: 10rpx;
            padding: 0rpx 30rpx 0rpx 5rpx;
          "
        ></image>
      </view>
    </view>
    <!-- 录音UI效果 -->
    <view class="record" :class="recording ? '' : 'hidden'">
      <view class="ing" :class="willStop ? 'hidden' : ''"
        ><view class="icon luyin2"></view
      ></view>
      <view class="cancel" :class="willStop ? '' : 'hidden'"
        ><view class="icon chehui"></view
      ></view>
      <view class="tis" :class="willStop ? 'change' : ''">{{ recordTis }}</view>
    </view>
  </view>
</template>
<script>
export default {
  data() {
    return {
      //文字消息
      tempFilePath: "",
      textMsg: "",
      json: "",
      //消息列表
      isHistoryLoading: false,
      scrollAnimation: false,
      scrollTop: 0,
      scrollToView: "",
      msgList: [],
      msgImgList: [],
      myuid: 0,

      //录音相关参数
      // #ifndef H5
      //H5不能录音
      RECORDER: uni.getRecorderManager(),
      // #endif
      isVoice: false,
      voiceTis: "按住 说话",
      recordTis: "手指上滑 取消发送",
      recording: false,
      willStop: false,
      initPoint: { identifier: 0, Y: 0 },
      recordTimer: null,
      recordLength: 0,

      //播放语音相关参数
      AUDIO: uni.createInnerAudioContext(),
      playMsgid: null,
      VoiceTimer: null,
      // 抽屉参数
      popupLayerClass: "",
      // more参数
      hideMore: true,
      //表情定义
      hideEmoji: true,

      //表情图片图床名称 ，由于我上传的第三方图床名称会有改变，所以有此数据来做对应，您实际应用中应该不需要

      //红包相关参数
      windowsState: "",
      redenvelopeData: {
        rid: null, //红包ID
        from: null,
        face: null,
        blessing: null,
        money: null,
      },
      appendContent: "",
      oldSendMsgIndex: 0,
      sSum: null,
      ifStopSock: false,
      questionList: [
        "什么是医保电子凭证?",
        "医保电子凭证如何修改密码?",
        "如何办理异地就医?",
        "什么是亲情账户?",
        "新生儿如何参保?",
      ],
    };
  },
  onLoad(option) {
    this.getMsgList();
    //语音自然播放结束
    this.AUDIO.onEnded((res) => {
      this.playMsgid = null;
    });
    // #ifndef H5
    //录音开始事件
    this.RECORDER.onStart((e) => {
      this.recordBegin(e);
    });
    //录音结束事件
    this.RECORDER.onStop((e) => {
      this.recordEnd(e);
    });
    // #endif
  },
  onShow() {
    if (uni.getStorageSync("userName")) {
      this.sSum = uni.getStorageSync("userName");
    } else {
      (this.sSum = Math.floor(Math.random() * 100)),
        uni.setStorageSync("userName", this.sSum);
    }
    console.log(this.sSum, "this.sSum");
    uni.connectSocket({
      url: `wss://abc.gszczn.com:18587/terminal/lma/chat/${this.sSum}`,
    });
    uni.onSocketOpen(function (res) {
      console.log("WebSocket连接已打开！");
    });
  

    this.json = "";
    uni.onSocketMessage((res) => {
      this.appendContent += res.data;
      this.leftMsg(this.appendContent, "text", this.oldSendMsgIndex == 0);
    });

    uni.onSocketError(function (res) {
      console.log("WebSocket连接打开失败，请检查！");
      uni.connectSocket({
        url: `wss://abc.gszczn.com:18587/terminal/lma/chat/${this.sSum}`,
      });
    });
    this.scrollTop = 9999999;

    //模板借由本地缓存实现发红包效果，实际应用中请不要使用此方法。
    //
    uni.getStorage({
      key: "redEnvelopeData",
      success: (res) => {
        let lastid = this.msgList[this.msgList.length - 1].msg.id;
        lastid++;
        let row = {
          type: "user",
          msg: {
            id: lastid,
            type: "redEnvelope",
            time: "",
            userinfo: {
              uid: 0,
              username: "大黑哥",
              face: "/static/img/face.jpg",
            },
            content: {
              blessing: res.data.blessing,
              rid: Math.floor(Math.random() * 1000 + 1),
              isReceived: false,
            },
          },
        };
        this.screenMsg(row);
        uni.removeStorage({ key: "redEnvelopeData" });
      },
    });
  },
  methods: {
    // 接受消息(筛选处理)
    screenMsg(msg) {
      //从长连接处转发给这个方法，进行筛选处理
      if (msg.type == "system") {
        // 系统消息
        switch (msg.msg.type) {
          case "text":
            this.addSystemTextMsg(msg);
            break;
          case "redEnvelope":
            this.addSystemRedEnvelopeMsg(msg);
            break;
        }
      } else if (msg.type == "user") {
        // 用户消息
        switch (msg.msg.type) {
          case "text":
            this.addTextMsg(msg);
            break;
          case "voice":
            this.addVoiceMsg(msg);
            break;
          case "img":
            this.addImgMsg(msg);
            break;
          case "redEnvelope":
            this.addRedEnvelopeMsg(msg);
            break;
        }
      }
      this.$nextTick(function () {
        // 滚动到底
        this.scrollToView = "msg" + msg.msg.id;
      });
    },
    questionBtn(type) {
      this.textMsg = type;
      this.sendText();
    },
    stopSock() {
      this.oldSendMsgIndex = 0;
      this.appendContent = "";
      this.ifStopSock = true;
      uni.closeSocket();
      uni.connectSocket({
        url: `wss://abc.gszczn.com:18587/terminal/lma/chat/${this.sSum}`,
      });
      uni.onSocketOpen((res) => {
        // uni.sendSocketMessage({ data: this.textMsg });
      });
    },
    //触发滑动到顶部(加载历史信息记录)
    loadHistory(e) {
      if (this.isHistoryLoading) {
        return;
      }
      this.isHistoryLoading = true; //参数作为进入请求标识，防止重复请求
      this.scrollAnimation = false; //关闭滑动动画
      let Viewid = this.msgList[0].msg.id; //记住第一个信息ID
      //本地模拟请求历史记录效果
      setTimeout(() => {
        // 消息列表
        let list = [];
        // 获取消息中的图片,并处理显示尺寸
        for (let i = 0; i < list.length; i++) {
          if (list[i].type == "user" && list[i].msg.type == "img") {
            list[i].msg.content = this.setPicSize(list[i].msg.content);
            this.msgImgList.unshift(list[i].msg.content.url);
          }
          list[i].msg.id = Math.floor(Math.random() * 1000 + 1);
          this.msgList.unshift(list[i]);
        }

        //这段代码很重要，不然每次加载历史数据都会跳到顶部
        this.$nextTick(function () {
          this.scrollToView = "msg" + Viewid; //跳转上次的第一行信息位置
          this.$nextTick(function () {
            this.scrollAnimation = true; //恢复滚动动画
          });
        });
        this.isHistoryLoading = false;
      }, 1000);
    },
    // 加载初始页面消息
    getMsgList() {
      // 消息列表
      let list = [
        {
          type: "user",
          msg: {
            id: 2,
            type: "text",
            time: "",
            userinfo: {
              uid: 1,
              username: "",
              face: "/static/img/im/face/face_2.jpg",
            },
            content: {
              text: "亲爱的用户您好，如果您有跟医保相关的疑问，欢迎向我提问，很高兴为您服务！",
            },
          },
        },
      ];

      this.msgList = list;
      // 滚动到底部
      this.$nextTick(function () {
        //进入页面滚动到底部
        this.scrollTop = 9999;
        this.$nextTick(function () {
          this.scrollAnimation = true;
        });
      });
    },
    //处理图片尺寸，如果不处理宽高，新进入页面加载图片时候会闪
    setPicSize(content) {
      // 让图片最长边等于设置的最大长度，短边等比例缩小，图片控件真实改变，区别于aspectFit方式。
      let maxW = uni.upx2px(350); //350是定义消息图片最大宽度
      let maxH = uni.upx2px(350); //350是定义消息图片最大高度
      if (content.w > maxW || content.h > maxH) {
        let scale = content.w / content.h;
        content.w = scale > 1 ? maxW : maxH * scale;
        content.h = scale > 1 ? maxW / scale : maxH;
      }
      return content;
    },

    //更多功能(点击+弹出)
    showMore() {
      this.isVoice = false;
      this.hideEmoji = true;
      if (this.hideMore) {
        this.hideMore = false;
        this.openDrawer();
      } else {
        this.hideDrawer();
      }
    },
    // 打开抽屉
    openDrawer() {
      this.popupLayerClass = "showLayer";
    },
    // 隐藏抽屉
    hideDrawer() {
      this.popupLayerClass = "";
      setTimeout(() => {
        this.hideMore = true;
        this.hideEmoji = true;
      }, 150);
    },

    //获取焦点，如果不是选表情ing,则关闭抽屉
    textareaFocus() {
      if (this.popupLayerClass == "showLayer" && this.hideMore == false) {
        this.hideDrawer();
      }
    },
    // 发送文字消息
    sendText() {
      this.hideDrawer(); //隐藏抽屉
      if (!this.textMsg) {
        return;
      }
      this.ifStopSock = false;
      uni.sendSocketMessage({ data: this.textMsg });
      this.sendMsg(this.textMsg, "text");
      this.loading = true;
      this.leftMsg("正在思考中...", "text", true);
      this.textMsg = ""; //清空输入框
    },

    // 发送消息
    sendMsg(content, type) {
      //消息发出后所做操作
      let lastid = this.msgList[this.msgList.length - 1].msg.id;
      lastid++;
      let msg = {
        type: "user",
        msg: {
          id: lastid,
          time: "",
          type: type,
          userinfo: {
            uid: 0,
            username: "大黑哥",
          },
          content: type == "text" ? { text: content } : { url: content.url },
        },
      };
      // 发送消息
      this.screenMsg(msg);
      // 定时器模拟对方回复,三秒
    },

    leftMsg(content, type, append) {
      let lastid = this.msgList[this.msgList.length - 1].msg.id;
      if (append) {
        lastid++;
      }
      let msg = {
        type: "user",
        msg: {
          id: lastid,
          time: "",
          type: type,
          userinfo: {
            uid: 1,
            username: "",
          },
          content: type == "text" ? { text: content } : { url: content.url },
        },
      };
      // 本地模拟发送消息
      this.screenMsg(msg);
    },

    // 添加文字消息到列表
    addTextMsg(msg) {
      // let msgItem = this.msgList[this.msgList.length - 1].msg;
      if (msg.msg.userinfo.uid == "0") {
        this.msgList.push(msg);
      } else {
        const findIndex = this.msgList.findIndex(
          (it) => it.msg.id === msg.msg.id
        );
        const index = msg.msg.content.text.indexOf(">>end<<");

        if (findIndex == -1) {
          this.oldSendMsgIndex = findIndex;
          this.msgList.push(msg);
          // uni.vibrateLong();
        } else {
          if (index === -1) {
            this.msgList.splice(findIndex, 1, msg);
          } else {
            this.oldSendMsgIndex = 0;
            this.appendContent = "";
          }
        }
      }
      this.chatScrollTop();
    },
    chatScrollTop() {
      this.$nextTick(() => {
        const query = uni.createSelectorQuery();
        query.select(".dialogue-box").boundingClientRect();
        query.select(".dialogue-box-content").boundingClientRect();
        query.exec((res) => {
          const scrollViewHeight = res[0].height;
          const scrollContentHeight = res[1].height;
          if (scrollContentHeight > scrollViewHeight) {
            const scrollTop = scrollContentHeight - scrollViewHeight;
            this.scrollTop = scrollTop;
          }
        });
      });
    },
    // 添加语音消息到列表
    addVoiceMsg(msg) {
      this.msgList.push(msg);
      console.log(this.msgList, "测试发过去的音频");
    },
    // 添加图片消息到列表
    addImgMsg(msg) {
      msg.msg.content = this.setPicSize(msg.msg.content);
      this.msgImgList.push(msg.msg.content.url);
      this.msgList.push(msg);
    },
    addRedEnvelopeMsg(msg) {
      this.msgList.push(msg);
    },
    // 添加系统文字消息到列表
    addSystemTextMsg(msg) {
      this.msgList.push(msg);
    },
    // 添加系统红包消息到列表
    addSystemRedEnvelopeMsg(msg) {
      this.msgList.push(msg);
    },

    sendSystemMsg(content, type) {
      let lastid = this.msgList[this.msgList.length - 1].msg.id;
      lastid++;
      let row = {
        type: "system",
        msg: { id: lastid, type: type, content: content },
      };
      this.screenMsg(row);
    },

    // 播放语音
    playVoice(msg) {
      this.playMsgid = msg.id;
      this.AUDIO.src = msg.content.url;
      this.$nextTick(function () {
        this.AUDIO.play();
      });
    },
    // 录音开始
    voiceBegin(e) {
      if (e.touches.length > 1) {
        return;
      }
      this.initPoint.Y = e.touches[0].clientY;
      this.initPoint.identifier = e.touches[0].identifier;
      this.RECORDER.start({ format: "wav" }); //录音开始,
    },
    //录音开始UI效果
    recordBegin(e) {
      this.recording = true;
      this.voiceTis = "松开 结束";
      this.recordLength = 0;
      this.recordTimer = setInterval(() => {
        this.recordLength++;
      }, 1000);
    },
    // 录音被打断
    voiceCancel() {
      this.recording = false;
      this.voiceTis = "按住 说话";
      this.recordTis = "手指上滑 取消发送";
      this.willStop = true; //不发送录音
      this.RECORDER.stop(); //录音结束
    },
    // 录音中(判断是否触发上滑取消发送)
    voiceIng(e) {
      if (!this.recording) {
        return;
      }
      let touche = e.touches[0];
      //上滑一个导航栏的高度触发上滑取消发送
      if (this.initPoint.Y - touche.clientY >= uni.upx2px(100)) {
        this.willStop = true;
        this.recordTis = "松开手指 取消发送";
      } else {
        this.willStop = false;
        this.recordTis = "手指上滑 取消发送";
      }
    },
    // 结束录音
    voiceEnd(e) {
      if (!this.recording) {
        return;
      }
      this.recording = false;
      this.voiceTis = "按住 说话";
      this.recordTis = "手指上滑 取消发送";
      this.RECORDER.stop(); //录音结束

      console.log("拿到录音啦", e, e.tempFilePath);
    },
    //录音结束(回调文件)
    recordEnd(e) {
      // debugger;
      console.log("拿语音url", e);
      clearInterval(this.recordTimer);
      if (!this.willStop) {
        let msg = {
          length: 0,
          url: e.tempFilePath,
        };
        let min = parseInt(this.recordLength / 60);
        let sec = this.recordLength % 60;
        min = min < 10 ? "0" + min : min;
        sec = sec < 10 ? "0" + sec : sec;
        msg.length = min + ":" + sec;
        console.log("e: " + JSON.stringify(e));
        uni.uploadFile({
          url: "https://abc.gszczn.com:18586/terminal/lma/identifyVoice",
          filePath: e.tempFilePath,
          name: "voiceFile",
          success: (uploadRes) => {
            console.log("上传成功", uploadRes);
            // this.leftMsg(uploadRes.data, "text");
            this.textMsg = uploadRes.data;
            this.sendText();
            // 在这里可以处理上传成功后的逻辑
          },
          fail(uploadErr) {
            console.log("上传失败", uploadErr);
            // 在这里可以处理上传失败后的逻辑
          },
        });
        // 将录音文件上传到后端
      } else {
        console.log("取消发送录音");
      }
      this.willStop = false;
    },

    // 切换语音/文字输入
    switchVoice() {
      this.hideDrawer();
      this.isVoice = this.isVoice ? false : true;
    },
    discard() {
      return;
    },
  },
};
</script>
<style lang="scss">
@import "@/static/css/style.scss";
</style>
